package game.utils;

import game.data.GameOption;
import game.worlds.IDisplay;
import game.worlds.IAttackDisplay;
import game.event.RoleEvent;
import game.worlds.GameEffect;
import game.worlds.GameRole;
import hx.geom.Matrix;
import hx.display.MovieClip;
import game.worlds.GameWorld;
import hx.display.DisplayObject;
import game.data.FrameData;
import haxe.DynamicAccess;
import game.data.ITimelineData;

using Reflect;

class ITimelineTools {
	public static function updateActionData(timeline:ITimelineData):Void {
		var frameKeys = [
			"originMoveX",
			"originMoveY",
			"originPointX",
			"originPointY",
			"originScaleX",
			"originScaleY",
			"originRotate",
			"originAlpha"
		];

		var mathKeys = [
			for (key in frameKeys) {
				var v = StringTools.replace(key, "origin", "");
				v.charAt(0).toLowerCase() + v.substr(1);
			}
		];

		var frameData:DynamicAccess<Int> = {
			originMoveX: 0,
			originMoveY: 0,
			originPointX: 0,
			originPointY: 0,
			originScaleX: 1,
			originScaleY: 1,
			originRotate: 0,
			originAlpha: 1
		};

		var frames = timeline.frames.copy();
		for (i => frame in timeline.frames) {
			// 进行复原重新计算
			for (i => key in frameKeys) {
				frame.setProperty(mathKeys[i], frameData[key]);
				frame.setProperty("_" + key, null);
			}
			frame.frame = i;
			for (effect in frame.effects) {
				effect.updateActionData();
			}
		}
		for (frameI => frame in frames) {
			// 进行复原重新计算
			for (i => key in frameKeys) {
				var lastFrame = timeline.getLastFrame(frame, key);
				var nextFrame = timeline.getNextFrame(frame, key);

				if (nextFrame != null) {
					var frameStep = nextFrame.frame - lastFrame.frame;
					// 获得帧数据，如果不存在，则使用默认数据
					var lastValue:Float = lastFrame.getProperty(key) ?? frameData[key];
					var nextValue:Float = nextFrame.getProperty(key) ?? frameData[key];
					var stepValue = (nextValue - lastValue) / frameStep;
					frame.setProperty(mathKeys[i], stepValue);
					frame.setProperty("_" + key, lastValue + stepValue * (frameStep - (nextFrame.frame - frame.frame)));
				} else {
					var lastFrame2 = frames[frameI - 1];
					// 没有过渡帧时，默认为0
					frame.setProperty(mathKeys[i], 0);
					if (lastFrame2 != null) {
						// 如果自已存在值时，必须优先使用自已的值，然后再考虑_key值，最后才考虑默认值
						frame.setProperty("_" + key, frame.getProperty(key) ?? lastFrame2.getProperty("_" + key) ?? frameData[key]);
					} else {
						frame.setProperty("_" + key, frameData[key]);
					}
				}
			}
		}
	}

	public static function getLastFrame(timeline:ITimelineData, frame:FrameData, key:String):FrameData {
		var i = frame.frame;
		while (i > 0) {
			if (timeline.frames[i].getProperty(key) != null) {
				return timeline.frames[i];
			}
			i--;
		}
		return timeline.frames[0];
	}

	public static function getNextFrame(timeline:ITimelineData, frame:FrameData, key:String):FrameData {
		var i = frame.frame + 1;
		while (i < timeline.frames.length) {
			if (timeline.frames[i].getProperty(key) != null) {
				return timeline.frames[i];
			}
			i++;
		}
		return null;
	}

	/**
	 * 计算缩放、旋转、透明度等实现
	 * @param dt 
	 */
	public static function updateTransform(display:MovieClip, frameData:FrameData, timeline:ITimelineData, offestX:Float, offestY:Float, scale:Float,
			dt:Float):Void {
		if (frameData == null || display.data == null) {
			return;
		}
		var dtScale = DtTools.mathTimeScale(dt);
		// 每帧经过时间
		var frameDt = 1 / timeline.fps;
		// 所需多少帧会到下一步
		var frameCounts = frameDt / GameOption.DT_FPS;
		var scaleX = frameData.scaleX / frameCounts * dtScale;
		var scaleY = frameData.scaleY / frameCounts * dtScale;
		var rotation = frameData.rotate;
		var alpha = frameData.alpha;
		var r = rotation * Math.PI / 180;

		var currentFrameCounts = Math.floor(@:privateAccess Math.min(display.duration, display.__time) / frameDt);

		scaleX *= currentFrameCounts;
		scaleY *= currentFrameCounts;
		r *= currentFrameCounts;
		alpha *= currentFrameCounts;

		var t = new Matrix();
		t.translate(offestX, offestY + display.data.rect.height / 2);

		var setScaleX:Float = @:privateAccess frameData._originScaleX + scaleX;
		var setScaleY:Float = @:privateAccess frameData._originScaleY + scaleY;

		t.scale(setScaleX * scale, setScaleY * scale);
		t.rotate(@:privateAccess frameData._originRotate * Math.PI / 180 + r);
		t.translate(0, -display.data.rect.height / 2 * scale);
		display.transform = t;
		display.alpha = @:privateAccess frameData._originAlpha + alpha;
	}

	/**
	 * 时间轴的统一更新位移逻辑，如果`display.body`存在对象时，则意味着这个对象将受到物理世界的影响。
	 * @param display 
	 * @param frameData 
	 * @param timeline 
	 * @param scale 
	 * @param dt 
	 */
	public static function updateMove(display:IDisplay, frameData:FrameData, timeline:ITimelineData, scale:Float, dt:Float):Void {
		if (frameData != null) {
			var dtScale = DtTools.mathTimeScale(dt);
			// 每帧经过时间
			var frameDt = 1 / timeline.fps;
			// 所需多少帧会到下一步
			var frameCounts = frameDt / GameOption.DT_FPS;
			var mX = frameData.moveX / frameCounts * dtScale * display.scaleX;
			var mY = frameData.moveY / frameCounts * dtScale;
			if (display.body != null) {
				display.body.velocity.x += mX * scale;
				display.body.velocity.y += mY * scale;
			} else {
				display.x += mX * scale;
				display.y += mY * scale;
			}
			#if editer
			if (display is GameRole) {
				@:privateAccess cast(display, GameRole).__lastPreviewMoveX = mX;
				@:privateAccess cast(display, GameRole).__lastPreviewMoveY = mY;
			}
			#end
		}
	}

	/**
	 * 解析帧上的特效数据
	 * @param currentFrameData 
	 * @param display 
	 */
	public static function parserGameEffect(currentFrameData:FrameData, display:IAttackDisplay):Void {
		if (currentFrameData != null && currentFrameData.effects.length > 0) {
			var isEffect = display is GameEffect;
			var role:GameRole = isEffect ? cast(display, GameEffect).role : cast display;
			for (effect in currentFrameData.effects) {
				var atlas = role.assets.getAtlas(effect.name);
				if (atlas != null) {
					var gameEffect = new GameEffect(display, effect.name);
					gameEffect.originData = effect;
					if (!isEffect)
						gameEffect.applyEffectData(effect, display.x, display.y, role.scaleX > 0 ? 1 : -1);
					else
						gameEffect.applyEffectData(effect, display.x, display.y, display.scaleX > 0 ? 1 : -1);
					role.world.displayBox.addChild(gameEffect);
					role.effects.push(gameEffect);
					if (role.hasEventListener(RoleEvent.CREATE_SKILL)) {
						var event = new RoleEvent(RoleEvent.CREATE_SKILL);
						event.data = gameEffect;
						role.dispatchEvent(event);
					}
				}
			}
		}
	}

	public static function addFrame(timeline:ITimelineData, frame:FrameData):Void {
		frame.timeline = timeline;
		timeline.frames.push(frame);
	};

	public static function removeFrame(timeline:ITimelineData, frame:FrameData):Void {
		if (timeline.frames.remove(frame)) {
			frame.timeline = null;
		}
	};
}
